home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Games Collection 1
/
software vault.zip
/
software vault
/
CDR10
/
ACK3D.ZIP
/
ENGINE
/
ACKASM.ASM
< prev
next >
Wrap
Assembly Source File
|
1993-08-24
|
24KB
|
939 lines
PAGE 80,132
TITLE - ACKASM.ASM - Assembly routines for 3D engine
.386P
;==============================================================================
; COMMAND LINE ASSEMBLY
; MASM /B63 /Z /D_Mx FILENAME;
;
; WHERE Mx SPECIFIES MODEL (l OR c) FOR LARGE OR COMPACT MODELS
;==============================================================================
INCLUDE ET.EQU
INCLUDE ET.MAC
ANGLE_30 equ 160
ANGLE_360 equ 1920
extrn _bMaps:DWORD
extrn _oMaps:DWORD
extrn _PageBegin:WORD
extrn _InvCosTable:DWORD
extrn _InvSinTable:DWORD
extrn _LongCosTable:DWORD
extrn _DistanceTable:WORD
extrn _AdjustTable:DWORD
extrn _CenterRow:WORD
extrn _MaxDistance:WORD
extrn _TopColor:WORD
extrn _BottomColor:WORD
extrn _WinStartX:WORD
extrn _WinEndX:WORD
extrn _WinWidth:WORD
extrn _WinColumnCount:WORD
extrn _WinStartY:WORD
extrn _WinEndY:WORD
extrn _WinStartOffset:WORD
extrn _WinLength:WORD
extrn _WinTopLength:WORD
extrn _WinBotLength:WORD
extrn _WinQuadTopLength:WORD
extrn _WinQuadBotLength:WORD
extrn _TopLongColor:DWORD
extrn _BotLongColor:DWORD
extrn _lowmask:BYTE
extrn _Walls:WORD
extrn _ScreenBuffer:DWORD
extrn _BkgdBuffer:DWORD
extrn _OverlayBuffer:DWORD
extrn _LightFlag:BYTE
extrn _WorkPalette:BYTE
PEXTRN _AckGetBitmapPtr
PEXTRN _AckLockPtr
PEXTRN _AckUnlockPtr
PUBLIC _AckSetVGAmode
PUBLIC _AckSetTextmode
PUBLIC _MakeCharLong
PUBLIC _AckDrawPage
PUBLIC _AckSetPalette
PUBLIC _AckBuildCeilingFloor
PUBLIC _AckReplaceBitmap
PUBLIC _AckOverlayBitmap
PUBLIC _draw_col2
SCREEN_SEG equ 0a000h ;segment of display memory in VGA mode 13h
_TEXT segment byte public use16 'CODE'
DGROUP group _DATA,_BSS
assume cs:_TEXT,ds:DGROUP
_TEXT ends
_DATA segment word public use16 'DATA'
_d@ label byte
_DATA ends
_BSS segment word public use16 'BSS'
_b@ label byte
_BSS ends
_TEXT SEGMENT byte public use16 'CODE'
ASSUME cs:_TEXT
;==============================================================================
; void AckSetVGAmode(void);
;==============================================================================
PBEGIN _AckSetVGAmode
push bp
mov ax,13h
int 10h ; Set 320x200x256
pop bp
ret
_AckSetVGAmode endp
;==============================================================================
;
;==============================================================================
PBEGIN _AckSetTextmode
push bp
mov ax,3
int 10h
pop bp
ret
_AckSetTextmode endp
;==============================================================================
; Fade the screen in from black to the palette specified
; Contributed by Mark Betz
;==============================================================================
AFIbeg equ [bp+ABASE]
AFIcnt equ [bp+ABASE+2]
AFIpal equ [bp+ABASE+4]
PBEGIN _AckFadeIn
push bp
mov bp,sp
push ds
push si
push di
mov cx,384
xor ax,ax
push ds
pop es
mov dx,offset DGROUP:_WorkPalette
push dx ; save offset of pal
xor bx, bx ; need to get the current palette into
mov cx, 100h ; pal using bios int 10h, 10h, 17h
mov ax, 1017h ; set up and generate the interrupt
int 10h ; read the palette registers into pal
pop di ; offset of pal, was in dx!
; get the palette pointer, then calculate the offset to the
; first byte processed, based on start, and the number of
; bytes to process based on count. Use the offset to adjust
; the string pointers in si and di, and leave the byte
; count in ax
lds si, AFIpal ; get address of target palette
mov ax, AFIbeg ; get offset of first palette byte to
mov bx, 3 ; be processed
mul bx
add si, ax ; adjust di and si point first byte in the
add di, ax ; target and temporary palettes
mov ax, AFIcnt ; find the number of bytes to be processed
mov bx, 3
mul bx ; leave it in ax
; clear the bytes in the triplets which will be operated on by
; the fade. All other registers are unaffected
push di ; save the starting offset into pal
push ax ; save the number of bytes to process
mov cx, ax ; set up a loop counter
xor ax, ax ; clear ax
rep stosb ; fill relevant range of pal with 0's
pop ax ; restore the number of bytes to process
pop di ; restore the starting offset into pal
mov cx, 64 ; 64 passes through fade loop
; the fade loop will execute 64 times. On each pass the inner
; loop adjusts the working palette, then waits for a blanking
; interval, and loads the working palette into the DAC
fade_loop:
push cx ; save the fade loop counter
push di ; save offset of first byte processed in
push si ; temp and target palettes
mov bl, cl ; outer loop count into bl
mov cx, ax ; load number of bytes to process into cx
; inner loop makes one pass through the palette for each pass
; through the outer loop. Each byte is incremented if it's
; target value is one greater than the outer loop count. Using
; this logic ensures that all bytes arrive at their target values
; on the same pass through the outer loop
pal_cmp_loop:
cmp bl, ds:[si] ; start incrementing when palette value
jns no_add ; is one greater than loop count
inc BYTE PTR es:[di]
no_add:
inc si ; point to the next byte in both palettes
inc di
loop pal_cmp_loop ; do the next byte
; setup for palette load. As much as possible was moved above the
; blanking interval wait, in order to maximize the amount of the
; blanking interval remaining in which to do the palette loading
mov bx, sp
mov di, ss:[bx+02] ; restore offset into pal without popping
mov cx, AFIcnt ; number of triplets to process
push ax ; need to use ax for port i/o
; monitor bit 1 of CRT controller's input status 1 register to
; sense a vertical blanking interval. Wait for any current vbi
; to end, then wait for the next full one to begin.
mov dx, 03DAh ; CRT controller input status 1 register
vbi_1:
in al, dx ; watch vertical blanking bit
test al,08h ; wait for it to clear to make sure
jnz vbi_1 ; we're not in a blanking interval
vbi_2:
in al, dx ; now wait for the start of the
test al,08h ; next blanking interval
jz vbi_2
; load the relevant triplets from pal into the VGA DAC palette
mov ah, BYTE PTR AFIbeg ; get first register to process into ah
mov dx, 03c8h ; DAC palette index register
pal_load_loop:
mov al, ah ; get next palette number to write
out dx, al ; write the register number to the dac
inc dx ; address dac data register
mov al, BYTE PTR es:[di] ; get first byte of triplet
out dx, al ; write it to the dac data register
inc di ; point to second byte
mov al, BYTE PTR es:[di] ; get second byte of triplet
out dx, al ; write it to the dac data register
inc di ; point to third byte
mov al, BYTE PTR es:[di] ; get third byte of triplet
out dx, al ; write it to the dac data register
inc di ; point to first byte of next triplet
dec dx ; address the dac index register
inc ah ; point to next palette register
loop pal_load_loop ; process next triplet
; clean-up for the next pass through the fade loop
pop ax ; restore ax
pop si ; restore the offset into palette
pop di ; restore the offset into pal
pop cx ; restore the fade loop counter
loop fade_loop ; do the next pass through the fade loop
pop di
pop si
pop ds
pop bp
ret
_AckFadeIn endp
;==============================================================================
; void AckFadeOut(int Begin,int Count);
; Contributed by Mark Betz
;==============================================================================
AFObeg equ [bp+ABASE]
AFOcnt equ [bp+ABASE+2]
PBEGIN _AckFadeOut
push bp
mov bp,sp
push ds
push si
push di
push ds ; get data segment into es
pop es
mov dx, offset DGROUP:_WorkPalette
push dx ; save offset of opal
xor bx, bx
mov cx, 100h
mov ax, 1017h ; bios read dac registers function
int 10h ; read the palette registers into opal
pop di ; offset of opal, was in dx!
mov ax, AFObeg ; get offset of first palette byte to
mov bx, 3 ; be processed
mul bx
add di, ax ; adjust offset into opal
mov ax, AFOcnt ; find the number of bytes to be processed
mov bx, 3
mul bx ; leave it in ax
mov cx, 64 ; 64 passes through fade loop
o_fade_loop:
push cx ; save the fade loop counter
push di ; save offset of first byte processed in
mov bl, cl ; we'll use the pass number as a threshold
mov cx, ax ; load number of bytes to process into cx
o_pal_cmp_loop:
cmp bl, es:[di] ; start decrementing when palette value
jnz o_no_dec ; is equal loop count (it will stay equal
dec BYTE PTR es:[di] ; to loop count for the rest of this pass)
o_no_dec:
inc di
loop o_pal_cmp_loop ; do the next byte
mov bx, sp ; need the stack pointer for a moment
mov di, ss:[bx] ; restore offset into pal without popping
mov cx, AFOcnt ; number of triplets to process
push ax ; need to use ax for port i/o
mov dx, 03DAh ; CRT controller input status 1 register
o_vbi_1:
in al, dx ; watch vertical blanking bit
test al,08h ; wait for it to clear to make sure
jnz o_vbi_1 ; we're not in a blanking interval
o_vbi_2:
in al, dx ; now wait for the start of the
test al,08h ; next blanking interval
jz o_vbi_2
mov ah, BYTE PTR AFObeg ; get first register to process into ah
mov dx, 03c8h ; DAC palette index register
o_pal_load_loop:
mov al, ah ; get next palette number to write
out dx, al ; write the register number to the dac
inc dx ; address dac data register
mov al, BYTE PTR es:[di] ; get first byte of triplet
out dx, al ; write it to the dac data register
inc di ; point to second byte
mov al, BYTE PTR es:[di] ; get second byte of triplet
out dx, al ; write it to the dac data register
inc di ; point to third byte
mov al, BYTE PTR es:[di] ; get third byte of triplet
out dx, al ; write it to the dac data register
inc di ; point to first byte of next triplet
dec dx ; address the dac index register
inc ah ; point to next palette register
loop o_pal_load_loop ; process next triplet
pop ax ; restore ax
pop di ; restore the offset into pal
pop cx ; restore the fade loop counter
loop o_fade_loop ; do the next pass through the fade loop
pop di
pop si
pop ds
pop bp
ret
_AckFadeOut endp
;==============================================================================
;
;==============================================================================
MCLch equ [bp+ABASE]
PBEGIN _MakeCharLong
push bp
mov bp,sp
mov ax,MCLch
mov ah,al
mov dx,ax
pop bp
ret
_MakeCharLong endp
;==============================================================================
; void AckDrawOverlay(UCHAR far *Screen,UCHAR far *Overlay);
;==============================================================================
ADOscrn equ [bp+ABASE]
ADOover equ [bp+ABASE+4]
PBEGIN _AckDrawOverlay
push bp
mov bp,sp
push ds
push si
push di
les di,dword ptr ADOscrn
lds si,dword ptr ADOover
mov bx,di ;Save screen offset
mov ax,ds
or ax,ax
jz ado90
ado10:
lodsw ;get length
or ax,ax
jz ado90 ;no more data
xchg cx,ax
lodsw ;get offset to move to
add di,ax
shr cx,1
rep movsw
rcl cx,1 ; catch any odd byte
rep movsb ; move one if there is an odd byte
mov di,bx ;Restore original screen offset
jmp ado10
ado90:
pop di
pop si
pop ds
pop bp
ret
_AckDrawOverlay endp
;==============================================================================
;
; 1. Take the compiled overlay buffer and moves the non-transparent portions
; over the top of the screen buffer.
;
; 2. Copies the area of the viewing window from the screen buffer to the
; actual screen.
;==============================================================================
DPWinStartOffset equ [BP+ABASE]
DPWinLength equ [BP+ABASE+2]
DPScreenBuffer equ [BP+ABASE+4]
DPWinWidth equ [bp+ABASE+8]
DPWinHeight equ [bp+ABASE+10]
DPWinStartX equ [bp+ABASE+12]
PBEGIN _AckDrawPage
push bp
mov bp,sp
push si
push di
push ds
mov cx,word ptr DPWinWidth;
mov bx,word ptr DPWinHeight;
mov di,word ptr DPWinStartOffset
add di,word ptr DPWinStartX
mov ax,SCREEN_SEG
mov es,ax
lds si,dword ptr DPScreenBuffer
add si,di ;Add starting offset to screen buffer
;------------------------------------------------------------------------------
; Removed for now, if flicker is noticed on faster machines, then it may have
; to be put back in.
;------------------------------------------------------------------------------
; mov dx,3dah
;fp030:
; in al,dx ;Wait until vertical retrace is off
; test al,8
; jnz fp030
;fp040:
; in al,dx ;Wait until vertical retrace resumes
; test al,8
; jz fp040
mov dx,cx ;Hold onto width
mov ax,320
sub ax,cx ;get bytes to next row
dec bx
jz fp060
fp050:
shr cx,1
rep movsw
rcl cx,1
rep movsb
mov cx,dx
add di,ax
add si,ax
dec bx
jnz fp050
fp060:
pop ds
pop di
pop si
pop bp
ret
_AckDrawPage endp
;==============================================================================
; void AckSetPalette(unsigned char far *PalBuf);
;==============================================================================
SPbuf equ [bp+ABASE]
PBEGIN _AckSetPalette
push bp
mov bp,sp
push ds
push si
lds si,dword ptr SPbuf
mov cx,256
xor bx,bx
cld
mov dx,3C8H
sp010:
mov al,bl
out dx,al
inc dx
lodsb
out dx,al
lodsb
out dx,al
lodsb
out dx,al
dec dx
inc bx
loop sp010
pop si
pop ds
pop bp
ret
_AckSetPalette endp
;==============================================================================
;
;void AckBuildCeilingFloor(UCHAR far *,int,int,int,int,int,int);
;==============================================================================
CFBkgdBuffer equ [bp+ABASE]
CFLightFlag equ [bp+ABASE+4]
CFTopColor equ [bp+ABASE+6]
CFBottomColor equ [bp+ABASE+8]
CFWinStartY equ [bp+ABASE+10]
CFWinEndY equ [bp+ABASE+12]
CFCenterRow equ [bp+ABASE+14]
PBEGIN _AckBuildCeilingFloor
push bp
mov bp,sp
push si
push di
les di,dword ptr CFBkgdBuffer
test byte ptr CFLightFlag,1 ;Is shading on
jz bcf_normal ;nope
jmp bcf_shade ;else create shaded buffer
bcf_normal:
mov cx,word ptr CFCenterRow
sub cx,word ptr CFWinStartY
inc cx
imul cx,320
mov ax,word ptr CFTopColor
rep stosb ;no need to be fast here
mov cx,word ptr CFWinEndY
sub cx,word ptr CFCenterRow
imul cx,320
mov ax,word ptr CFBottomColor
rep stosb
jmp bcf_done ;exit routine
bcf_shade:
mov bx,word ptr CFCenterRow
sub bx,word ptr CFWinStartY ;Number of video rows
inc bx
mov cx,bx ;Hold onto total rows
shr bx,3 ;Turn into 8 zones
mov ax,word ptr CFTopColor
mov ah,al ;Top color to use
mov dx,4000H ;set shading for next zone
call FillInZone
mov dx,4040H
call FillInZone
mov dx,8040H
call FillInZone
mov dx,8080H
call FillInZone
mov dx,0C080H
call FillInZone
mov dx,0C0C0H
call FillInZone
mov dx,0FFC0H
call FillInZone ;This takes care of top 8 zones
mov dx,0FFFFH
call FillInZone
xchg ax,bx ;ax has rows per zone
xchg cx,bx ;bx has total rows for top color
shl ax,3 ;x 8 to get total rows
sub bx,ax ;get remaining rows if odd
jz bcf010 ;no odd rows to fill
mov dx,0FFFFH
call FillInZone
bcf010:
mov bx,word ptr CFWinEndY
sub bx,word ptr CFCenterRow
mov cx,bx
shr bx,3
mov ax,bx
shl ax,3
sub cx,ax ;any odd rows to fill?
jz bcf020 ;nope
push bx ;save rows per zone
mov bx,cx
mov dx,0FFFFH
call FillInZone
pop bx
bcf020:
mov ax,word ptr CFBottomColor
mov ah,al
mov dx,0FFFFH
call FillInZone
mov dx,0FFC0H
call FillInZone
mov dx,0C0C0H
call FillInZone
mov dx,0C080H
call FillInZone
mov dx,8080H
call FillInZone
mov dx,8040H
call FillInZone
mov dx,4040H
call FillInZone
mov dx,4000H
call FillInZone
bcf_done:
pop di
pop si
mov sp,bp
pop bp
ret
_AckBuildCeilingFloor endp
;==============================================================================
; Local routine, called by BuildCeilingFloor
; Entry: BX = number of rows to fill
; DX = Shading values for odd/even rows
; AX = base color value
;
; Exit: Di advanced bx * 160 bytes, all other registers preserved
;
;==============================================================================
FillInZone proc near
push bx
push cx
push si
mov si,ax
fiz010:
test bx,1 ;check odd/even row
jz fiz020
or ax,dx
jmp short fiz030
fiz020:
or al,dh ;swap which bytes are used
or ah,dl
fiz030:
mov cx,160 ;move in one row
rep stosw
mov ax,si ;restore base color
dec bx ;bump number of rows
jnz fiz010
pop si
pop cx
pop bx
ret
FillInZone endp
;==============================================================================
; void AckReplaceBitmap(UCHAR far *xGrid,UCHAR far *yGrid,UCHAR OldBmp,UCHAR NewBmp);
; Replaces OldBmp numbers with NewBmp numbers in x and y grid arrays
;==============================================================================
ARBxGrid equ [bp+ABASE]
ARByGrid equ [bp+ABASE+4]
ARBold equ [bp+ABASE+8]
ARBnew equ [bp+ABASE+10]
PBEGIN _AckReplaceBitmap
push bp
mov bp,sp
push ds
push si
lds si,ARBxGrid
mov cx,4160 ;65x64
mov bl,byte ptr ARBold
mov bh,byte ptr ARBnew
arb010:
lodsw ;get flags and bitmap
cmp al,bl ;old bitmap?
jne arb020 ;nope
mov ds:[si-2],bh ;else plug in new bitmap
arb020:
loop arb010
lds si,ARByGrid
mov cx,4160 ;65x64
arb030:
lodsw ;get flags and bitmap
cmp al,bl ;old bitmap?
jne arb040 ;nope
mov ds:[si-2],bh ;else plug in new bitmap
arb040:
loop arb030
pop si
pop ds
pop bp
ret
_AckReplaceBitmap endp
;==============================================================================
; void AckOverlayBitmap(UCHAR far *dest,UCHAR far *src);
; Overlays non-transparent colors of source bitmap onto destination bitmap
;==============================================================================
AOBdest equ [bp+ABASE]
AOBsrc equ [bp+ABASE+4]
PBEGIN _AckOverlayBitmap
push bp
mov bp,sp
push ds
push si
push di
push word ptr AOBdest+2
push word ptr AOBdest
call _AckLockPtr
add sp,4
or dx,dx ;null segment?
jz aob090 ;yep, not enough memory
push dx
push ax ;save destination ptr
push word ptr AOBsrc+2
push word ptr AOBsrc
call _AckLockPtr
add sp,4
or dx,dx ;error getting pointer?
jnz aob010 ;nope, okay so far
call _AckUnlockPtr ;Unlock the DX:AX above
add sp,4
jmp short aob090
aob010:
mov fs,dx
mov si,ax ;Source
mov bx,ax ;Hold onto source offset
pop di
pop es ;Get destination from DX:AX above
mov dx,di ;hold onto destination offset
mov cx,4096 ;64x64 bitmap
aob020:
mov al,fs:[si] ;get source pixel
or al,al
jz aob030
mov es:[di],al
aob030:
inc si
inc di
loop aob020
push es
push dx ;dest bitmap
push fs
push bx ;source bitmap
call _AckUnlockPtr
add sp,4
call _AckUnlockPtr ;now unlock destination
add sp,4
aob090:
pop di
pop si
pop ds
pop bp
ret
_AckOverlayBitmap endp
;==============================================================================
; AckCopyBackground(UCHAR far *scrn,UCHAR far *bkgd,int len,int offset);
;==============================================================================
ACBscrn equ [bp+ABASE]
ACBbkgd equ [bp+ABASE+4]
ACBlen equ [bp+ABASE+8]
ACBoff equ [bp+ABASE+10]
PBEGIN _AckCopyBackground
push bp
mov bp,sp
push ds
push si
push di
;------------------------------------------------------------------------------
; Quickly transfer the pre-built background ceiling and floor to the screen.
;------------------------------------------------------------------------------
les di,dword ptr ACBscrn
add di,word ptr ACBoff
mov cx,word ptr ACBlen ;Number of DWORDS to move
lds si,dword ptr ACBbkgd ;Pre-built buffer
rep movsd
pop di
pop si
pop ds
pop bp
ret
_AckCopyBackground endp
;==============================================================================
; draw_col2(int Col,int slice,int dist,int width,int ht,UCHAR far *Wall,
; UCHAR far *Screen,UCHAR far *Pal,int light,int offset);
; Contributed by Jaimi McEntire
;==============================================================================
DCcol equ [bp+ABASE]
DCslice equ [bp+ABASE+2]
DCdist equ [bp+ABASE+4]
DCwidth equ [bp+ABASE+6]
DCht equ [bp+ABASE+8]
DCwall equ [bp+ABASE+10]
DCscrn equ [bp+ABASE+14]
DCPal equ [bp+ABASE+18]
DClight equ [bp+ABASE+22]
DChoff equ [bp+ABASE+24]
DCangle equ [bp-2]
PBEGIN _draw_col2
push bp
mov bp,sp
sub sp,4
push ds
push si
push di
mov word ptr DCangle,0
mov edx,0
mov esi,0
mov ax,DCdist ; get distance to object
shr ax,6 ; divide it by 64 to get zones.
cmp ax,15 ; make sure zone doesn't go beyond 15
jl zoneokay
mov ax,15
zoneokay:
; Good place for light modifier to modify zone
shl ax,8 ; mult by 256 to get offset into paltables.
lfs dx,dword ptr DCPal ; point FS:DX at PalTables
cmp word ptr DClight,0
jz zonelight
add dx,ax ; FS:DX points to corrected palette for zone.
zonelight:
les di,dword ptr DCscrn ; ES:DI point to area we are painting
;/ mov ax,column
;/ cmp ax,ViewX
;/ jl outtahere ; don't bother to draw a column we wont see.
;/ cmp ax,ViewX2
;/ jge outtahere
;/ sub ax,ViewX
;/ mov column,ax ; adjust column for offset into buffer.
lds si,DCwall ; DS:SI point to wall buffer
;;; mov bx,DCht ; center row.
;;; imul bx,word ptr DCwidth
mov bx,DChoff ; Pick up offset to center of viewport
add bx,word ptr DCcol
add di,bx ; es:di now point at starting area (top run)
mov bx,di
add bx,DCwidth ; es:bx points to 1 down (for bottom run)
mov cx,0 ; ht.
mov ax,DCslice
shl ax,6 ; mult slice by 64
add ax,si ; add in offset to wall bitmap
mov DCslice,ax ; save it
mov eax,0
looptop:
movzx ax,ch ; current ht
mov si,31 ; base to start with
sub si,ax ; base - ht = row
add si,DCslice ; plus column start to point at the pixel.
mov al,ds:[si] ; mov al,offset slice[esi]
or al,al ; see if transparent
jz blank ; yes, don't draw this pixel
mov al,fs:[edx][eax] ; added this line to get correct shading.
mov es:[di],al
blank:
movzx si,ch ; use a cool 386 instruction to accomplish
add si,32 ; same as mov ax,cx; shr ax,8 !!
add si,DCslice ; add in starting column
mov al,ds:[si]
or al,al
je blank2
mov al,fs:[edx][eax] ; added this line to shade it.
mov es:[bx],al
blank2:
mov ax,DCwidth
sub di,ax ; point to the next two dest pixels.
add bx,ax ; point to the next two dest pixels.
add cx,word ptr DCdist ; add distance to ht adjuster.
cmp ch,32 ; cmp to 32 (1 half our bm size)
jge outtahere ; get out if bitmap done.
;;;; inc word ptr DCangle
mov ax,DCangle
inc ax
cmp ax,word ptr DCht ; if half height,
jge outtahere ; then leave.
mov DCangle,ax
jmp looptop
outtahere:
pop di
pop si
pop ds
mov sp,bp
pop bp
ret
_draw_col2 endp
_TEXT ENDS
END